﻿// Partial Copyright (c) LogoUI Software Solutions LTD
// Author: Vladislav Spivak
// This source file is the part of LogoFX Framework http://logofx.codeplex.com
// See accompanying licences and credits.

//based on, but not limited to http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2010/03/09/mef-and-the-deploymentcatalog.aspx
#if SILVERLIGHT

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;

namespace LogoFX.Composition
{
    public partial class DeploymentCatalogLoader
    {
        public class ConfigLoadHelper
        {
            class GroupItemsTuple
            {
                public DeploymentCatalogConfigGroup Item1;
                public IEnumerator<DeploymentCatalogConfigItem> Item2;

                public GroupItemsTuple(DeploymentCatalogConfigGroup item1,
                  IEnumerator<DeploymentCatalogConfigItem> item2)
                {
                    this.Item1 = item1;
                    this.Item2 = item2;
                }
            }
            public ConfigLoadHelper(DeploymentCatalogConfig config)
            {
                this.config = config;
            }
            public void LoadAsync(
              Action<DeploymentCatalogConfig> loadedAction,
              Action<DeploymentCatalogConfigGroup> groupLoadedAction,
              Action<DeploymentCatalogConfigItem, DeploymentCatalog, Exception> itemLoadedAction)
            {
                this.groupEnumerator = GetEnumerator();
                this.loadedAction = loadedAction;
                this.groupLoadedAction = groupLoadedAction;
                this.itemLoadedAction = itemLoadedAction;
                LoadNextGroupAsync();
            }
            IEnumerator<GroupItemsTuple> GetEnumerator()
            {
                foreach (var group in
                  this.config.ConfigurationGroups.OrderBy(g => g.Priority))
                {
                    yield return new GroupItemsTuple(group,
                      group.Catalogs.AsEnumerable().GetEnumerator());
                }
            }
            void LoadNextGroupAsync()
            {
                if (this.groupEnumerator.MoveNext())
                {
                    LoadNextGroupItemAsync();
                }
                else
                {
                    this.loadedAction(this.config);
                }
            }
            private static readonly Dictionary<string, DeploymentCatalog> Catalogs = new Dictionary<string, DeploymentCatalog>();
            void LoadNextGroupItemAsync()
            {
                while (true)
                {
                    if (this.groupEnumerator.Current.Item2.MoveNext())
                    {
                        DeploymentCatalog catalog;
                        
                        if (Catalogs.TryGetValue(this.groupEnumerator.Current.Item2.Current.Uri, out catalog))
                            continue;

                        catalog = new DeploymentCatalog(
                            this.groupEnumerator.Current.Item2.Current.Uri);

                        catalog.DownloadCompleted += (s, e) =>
                                                         {
                                                             this.itemLoadedAction(
                                                                 this.groupEnumerator.Current.Item2.Current, catalog,
                                                                 e.Error);

                                                             if(e.Error!=null)
                                                             {
                                                                 throw e.Error;
                                                             }
                                                             // we stop on the first error and load no more...
                                                             if (e.Error == null)
                                                             {
                                                                 Catalogs[catalog.Uri.ToString()] = catalog;
                                                                 LoadNextGroupItemAsync();
                                                             }
                                                         };

                        catalog.DownloadAsync();
                        
                    }
                    else
                    {
                        this.groupLoadedAction(this.groupEnumerator.Current.Item1);
                        LoadNextGroupAsync();
                    }
                    break;
                }
            }
            DeploymentCatalogConfig config;
            IEnumerator<GroupItemsTuple> groupEnumerator;
            Action<DeploymentCatalogConfig> loadedAction;
            Action<DeploymentCatalogConfigGroup> groupLoadedAction;
            Action<DeploymentCatalogConfigItem, DeploymentCatalog, Exception> itemLoadedAction;

        }
    }
}
#endif
